package com.hnedu.util;

import org.apache.struts.util.MessageResources;
import org.apache.struts.util.MessageResourcesFactory;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class EncodeMessageResources extends MessageResources {

  public EncodeMessageResources(MessageResourcesFactory factory,
                                    String config) {
        super(factory, config);
        log.info("Initializing, config='" + config + "'");
  }

  /**
   * Construct a new PropertyMessageResources according to the
   * specified parameters.
   *
   * @param factory The MessageResourcesFactory that created us
   * @param config The configuration parameter for this MessageResources
   * @param returnNull The returnNull property we should initialize with
   */
  public EncodeMessageResources(MessageResourcesFactory factory,
                                  String config, boolean returnNull) {

      super(factory, config, returnNull);
      log.info("Initializing, config='" + config +
               "', returnNull=" + returnNull);

  }


  // ------------------------------------------------------------- Properties


  /**
   * The set of locale keys for which we have already loaded messages, keyed
   * by the value calculated in <code>localeKey()</code>.
   */
  protected HashMap locales = new HashMap();


  /**
   * The <code>Log</code> instance for this class.
   */
  protected static final Log log =
      LogFactory.getLog(EncodeMessageResources.class);


  /**
   * The cache of messages we have accumulated over time, keyed by the
   * value calculated in <code>messageKey()</code>.
   */
  protected HashMap messages = new HashMap();


  // --------------------------------------------------------- Public Methods


  /**
   * Returns a text message for the specified key, for the default Locale.
   * A null string result will be returned by this method if no relevant
   * message resource is found for this key or Locale, if the
   * <code>returnNull</code> property is set.  Otherwise, an appropriate
   * error message will be returned.
   * <p>
   * This method must be implemented by a concrete subclass.
   *
   * @param locale The requested message Locale, or <code>null</code>
   *  for the system default Locale
   * @param key The message key to look up
   * @return text message for the specified key and locale
   */
  public String getMessage(Locale locale, String key) {

      if (log.isDebugEnabled()) {
          log.debug("getMessage(" + locale + "," + key + ")");
      }

      // Initialize variables we will require
      String localeKey = localeKey(locale);
      String originalKey = messageKey(localeKey, key);
      String messageKey = null;
      String message = null;
      int underscore = 0;
      boolean addIt = false;  // Add if not found under the original key

      // Loop from specific to general Locales looking for this message
      while (true) {

          // Load this Locale's messages if we have not done so yet
          loadLocale(localeKey);

          // Check if we have this key for the current locale key
          messageKey = messageKey(localeKey, key);
          synchronized (messages) {
              message = (String) messages.get(messageKey);
              if (message != null) {
                  if (addIt)
                      messages.put(originalKey, message);
                  return (message);
              }
          }

          // Strip trailing modifiers to try a more general locale key
          addIt = true;
          underscore = localeKey.lastIndexOf("_");
          if (underscore < 0)
              break;
          localeKey = localeKey.substring(0, underscore);

      }

      // Try the default locale if the current locale is different
      if (!defaultLocale.equals(locale)) {
          localeKey = localeKey(defaultLocale);
          messageKey = messageKey(localeKey, key);
          loadLocale(localeKey);
          synchronized (messages) {
              message = (String) messages.get(messageKey);
              if (message != null) {
                  messages.put(originalKey, message);
                  return (message);
              }
          }
      }

      // As a last resort, try the default Locale
      localeKey = "";
      messageKey = messageKey(localeKey, key);
      loadLocale(localeKey);
      synchronized (messages) {
          message = (String) messages.get(messageKey);
          if (message != null) {
              messages.put(originalKey, message);
              return (message);
          }
      }

      // Return an appropriate error indication
      if (returnNull)
          return (null);
      else
          return ("???" + messageKey(locale, key) + "???");

  }


  // ------------------------------------------------------ Protected Methods


  /**
   * Load the messages associated with the specified Locale key.  For this
   * implementation, the <code>config</code> property should contain a fully
   * qualified package and resource name, separated by periods, of a series
   * of property resources to be loaded from the class loader that created
   * this PropertyMessageResources instance.  This is exactly the same name
   * format you would use when utilizing the
   * <code>java.util.PropertyResourceBundle</code> class.
   *
   * @param localeKey Locale key for the messages to be retrieved
   */
  protected void loadLocale(String localeKey) {

      if (log.isTraceEnabled()) {
          log.trace("loadLocale(" + localeKey + ")");
      }

      // Have we already attempted to load messages for this locale?
      synchronized (locales) {
          if (locales.get(localeKey) != null)
              return;
          locales.put(localeKey, localeKey);
      }

      // Set up to load the property resource for this locale key, if we can
      String name = config.replace('.', '/');
      if (localeKey.length() > 0)
          name += "_" + localeKey;
      name += ".properties";
      InputStream is = null;
      Properties props = new Properties();

      // Load the specified property resource
      try {
          if (log.isTraceEnabled()) {
              log.trace("  Loading resource '" + name + "'");
          }
          ClassLoader classLoader =
              Thread.currentThread().getContextClassLoader();
          if (classLoader == null) {
              classLoader = this.getClass().getClassLoader();
          }
          is = classLoader.getResourceAsStream(name);
          if (is != null) {
              props.load(is);
              is.close();
          }
          if (log.isTraceEnabled()) {
              log.trace("  Loading resource completed");
          }
      } catch (Throwable t) {
          log.error("loadLocale()", t);
          if (is != null) {
              try {
                  is.close();
              } catch (Throwable u) {
                  ;
              }
          }
      }

      // Copy the corresponding values into our cache
      if (props.size() < 1)
          return;
      synchronized (messages) {
          Enumeration names = props.keys();
          while (names.hasMoreElements()) {
              String key = (String) names.nextElement();
              if (log.isTraceEnabled()) {
                  log.trace("  Saving message key '" +
                            messageKey(localeKey, key));
              }
              messages.put(messageKey(localeKey, key),
                         StringUtils.isoToGb(props.getProperty(key)) );
          }
      }

  }


}
